﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Reflection;

namespace FCMS.Extensions
{
    public enum AttachDataKey 
    { 
        DisplayName,
        Style
    }

    [AttributeUsage(AttributeTargets.All, AllowMultiple = true)]
    public class AttachDataAttribute : Attribute
    {
        public AttachDataAttribute(object key, object value)
        {
            this.Key = key;
            this.Value = value;
        }

        public AttachDataAttribute() { }

        public object Key { get; set; }

        public object Value { get; set; }
    }

    public static class AttachDataExtensions
    {
        public static object GetAttachedData(this ICustomAttributeProvider provider, object key)
        {
            var attributes = (AttachDataAttribute[])provider.GetCustomAttributes(typeof(AttachDataAttribute), false);
            return attributes.First(a => a.Key.Equals(key)).Value;
        }

        public static T GetAttachedData<T>(this ICustomAttributeProvider provider, object key)
        {
            return (T)provider.GetAttachedData(key);
        }

        public static object GetAttachedData(this Enum value, object key)
        {
            return value.GetType().GetField(value.ToString()).GetAttachedData(key);
        }

        public static T GetAttachedData<T>(this Enum value, object key)
        {
            return (T)value.GetAttachedData(key);
        }

        private static Dictionary<ICustomAttributeProvider, object> s_dictExtensionInstances = new Dictionary<ICustomAttributeProvider, object>();
        private static object s_dictExtensionMutex = new object();

        public static T GetExtensionInstance<T>(this ICustomAttributeProvider provider) where T : class
        {
            if (!s_dictExtensionInstances.ContainsKey(provider))
            {

                lock (s_dictExtensionMutex)
                {
                    if (!s_dictExtensionInstances.ContainsKey(provider))
                    {
                        s_dictExtensionInstances[provider] = CreateExtensionInstance<T>(provider);
                    }
                }
            }

            return (T)s_dictExtensionInstances.TryGetValue(provider);

        }

        private static T CreateExtensionInstance<T>(ICustomAttributeProvider provider) where T : class
        {
            var attributes = (AttachDataAttribute[])provider.GetCustomAttributes(typeof(AttachDataAttribute), false);

            var result = (T)typeof(T).GetConstructor(new Type[0]).Invoke(null);
            var properties = result.GetType().GetProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.Instance | BindingFlags.IgnoreCase);

            var query =
                from e in attributes
                select new
                {
                    Attribute = e,
                    property = properties.SingleOrDefault(p => p.Name.ToLower() == e.Key.ToString().ToLower())
                };

            foreach (var pair in query)
            {
                pair.property.SetValue(result, pair.Attribute.Value, null);
            }

            return result;
        }

        public static T GetExtensionInstance<T>(this Enum value) where T : class
        {
            return value.GetType().GetField(value.ToString()).GetExtensionInstance<T>();
        }
    }
}
